Docker 的 Build Cache
機制,可以在 build image 的過程中得到加速,
今天讓我們來對它做點研究,瞭解如何在實際應用上帶來幫助。
如果 D2 跟 D5 有跟著做的讀者,當你對相同的程式碼建置第二次時,會發現第二次的過程瞬間就完成了,快到不像有建置一樣,
Docker 確實有執行建置,然而,要說沒建置,也對,因為此時 Docker 並沒有建立出新的 image,
讓我們拿 D5 的建置過程來看看:
$ sudo docker build . -t hello-world-server
Sending build context to Docker daemon 48.64kB
Step 1/6 : FROM node:16-slim
---> 572389d8c38d
Step 2/6 : WORKDIR /app
---> Running in dae5dd7b2627
Removing intermediate container dae5dd7b2627
---> 4541c7e49a33
Step 3/6 : COPY ./package*.json ./
---> 29534be2c19c
Step 4/6 : RUN npm ci
---> Running in aa9b89c42d52
added 57 packages, and audited 58 packages in 1s
7 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
npm notice
npm notice New minor version of npm available! 8.15.0 -> 8.19.2
npm notice Changelog: <https://github.com/npm/cli/releases/tag/v8.19.2>
npm notice Run `npm install -g npm@8.19.2` to update!
npm notice
Removing intermediate container aa9b89c42d52
---> 582837243791
Step 5/6 : COPY . .
---> fb71c9523268
Step 6/6 : CMD ["npm", "start"]
---> Running in eda5c7a196a7
Removing intermediate container eda5c7a196a7
---> b33e04f2acb7
Successfully built b33e04f2acb7
Successfully tagged hello-world-server:latest
$ sudo docker build . -t hello-world-server
Sending build context to Docker daemon 48.64kB
Step 1/6 : FROM node:16-slim
---> 572389d8c38d
Step 2/6 : WORKDIR /app
---> Using cache
---> 4541c7e49a33
Step 3/6 : COPY ./package*.json ./
---> Using cache
---> 29534be2c19c
Step 4/6 : RUN npm ci
---> Using cache
---> 582837243791
Step 5/6 : COPY . .
---> Using cache
---> fb71c9523268
Step 6/6 : CMD ["npm", "start"]
---> Using cache
---> b33e04f2acb7
Successfully built b33e04f2acb7
Successfully tagged hello-world-server:latest
建置出來的 Docker image,其實是一層一層的,稱之為 Image Layer
,
可以看到前面 Docker 輸出的過程,寫了 Step m/n
,每一個步驟就會產生一層 Layer,
為什麼要有這個結構呢?這是一個容量與建置速度的最佳化,
不同 Image 之間,有可能前幾層都是相同的內容,既然已經知道內容相同,那儲存時就只要存一份並共用就好了,
同時建置時也不用每次都重建,直接拿已存在的相同 Layer 來接續建置就好了,
因此容量跟建置速度都可以藉此得到改善。
接下來我們可以在第二次的輸出中發現 ---> Using cache
的字樣,這代表了 Docker 在 Cache 中與這一層相同的內容,因此直接使用並跳到下一步,這裡的 Cache 就被稱為 Build Cache
,
(因此這裡 Build Cache
的 Build
是個名詞,用來形容這是建置過程的 Cache)
我們來做點嘗試:
利用 time
指令來測測看建置速度差異:
(尚未建置 image 的狀態)
$ time sudo docker build . -t hello-world-server
Sending build context to Docker daemon 48.64kB
Step 1/6 : FROM node:16-slim
---> 572389d8c38d
...
Step 6/6 : CMD ["npm", "start"]
---> Running in c166f0156483
Removing intermediate container c166f0156483
---> a35fdeba8e8c
Successfully built a35fdeba8e8c
Successfully tagged hello-world-server:latest
real 0m3.354s
user 0m0.032s
sys 0m0.007s
$ time sudo docker build . -t hello-world-server
Sending build context to Docker daemon 48.64kB
Step 1/6 : FROM node:16-slim
---> 572389d8c38d
Step 2/6 : WORKDIR /app
---> Using cache
...
Step 6/6 : CMD ["npm", "start"]
---> Using cache
---> a35fdeba8e8c
Successfully built a35fdeba8e8c
Successfully tagged hello-world-server:latest
real 0m0.094s
user 0m0.021s
sys 0m0.017s
3.3 秒 => 0.09 秒
雖然不多,可以發現時間上有改善,
但因為我們的範例很小,自然就看不到多大的差異,
--cache-from
有時,Docker 並不會準確地檢查到 Cache,但已存在的 Image 確實有可以重複使用的地方,
這時我們就可以在建置時加入 --cache-from
這個參數,明確告訴 Docker 要使用什麼 Image 的 Cache 資料,
$ sudo docker build . -t hello-world-server --cache-from another-server
Docker 官網也有針對 Build Cache 寫了一些建議,有興趣的讀者也可以進一步參考 Leverage build cache
這個區塊的內容。